#include <iostream>
#include <string>
#include <functional>

typedef std::function<void(int i, double d, std::string s, char c)> my_t;

void Print1(const std::string& str)
{
    std::cout << str << std::endl;
}

void func(int num, my_t my)
{
    my(10, 20.5, "abcd", 'a');  
    // 无论最后你怎么给包装器对象传递参数，这都是徒劳的
    // 因为bind已经将可调用对象print的参数给绑死了，callback实际调用的就是print(“chb”)这个函数。
}

void test1()
{
    //function是一种函数包装器，就是让函数也能像对象一样去调用

    // 下面的用例代码就可以很好的说明，bind生成的可调用对象的类型是完全适配包装器的，不管包装器的类型是什么，bind生成的可调用对象都可以传过去

    my_t my = std::bind(&Print1, "chb");
    std::function<void(int)> func1 = std::bind(&Print1, "chb");
    std::function<void()> func2 = std::bind(&Print1, "chb");                // 注意，function无参的写法是要加()，代表无参
    std::function<void(int, double)> func3 = std::bind(&Print1, "chb");

    func(100, std::bind(&Print1, "chb"));
}


void Print(const std::string &str, int num)
{
    std::cout << str << ":" << num << std::endl;
}

void test2()
{
    auto func0 = std::bind(&Print, "nihao", 200);
    auto func1 = std::bind(&Print, "hello", std::placeholders::_1);
    auto func2 = std::bind(&Print, std::placeholders::_1, std::placeholders::_2);
    auto func3 = std::bind(&Print, std::placeholders::_2, std::placeholders::_1);

    // func1("nihao", 250);     // err，因为第一个参数已经被绑死了，且占位符只有一个，所以只能传一个参数
    func0("a", 9, 100, 1000);   // 这个是因为都绑死了，传啥都无济于事

    func1(250);

    func2("hhh", 250);          // 对应占位符的名称，如果是_1，则对应原函数的第一个参数，与位置无关
    func3(250, "hhh");
}

int main()
{
    test1();
    test2();
    return 0;
}